process.env.TZ = 'Asia/Shanghai';

fs = require('fs');
mysql = require('mysql');

http = require('http');

uim = require('./uim.js');

constains = require('constants');

var qs = require('querystring');
const urlLib = require('url');//处理url相关

// 载入环境配置（以下划线开头的配置表示允许在运行中重新赋值并立即生效）
ENV = config = require('./env.config.js').config;

console.log('----------------------------------------------');
console.log('已初始环境变量', ENV);
console.log('----------------------------------------------');
ENV._DEPLOY_APP_ID = uim.createSafeString({
    int_unique: BigInt(ENV.APP_ID),
    int_tag: uim.config.enum.DEPLOY_APP_ID
});
console.log('应用编号：' + ENV._DEPLOY_APP_ID);
console.log('请将以上应用编号配置到前端uim.init.js中。');
console.log('----------------------------------------------');

//创建数据库连接池
conn_pool = mysql.createPool(ENV.MYSQL);

respool_area_list = {};
var init_respool_area_list = function () {
    // 初始资源池区域列表
    // respool_area_list = [
    //     1: {
    //         respool_area_id: 1,
    //         respool_area_name: '华北1区',
    //         description: '内蒙',
    //         console_redis_port: 26379,
    //         console_redis_host: '103.45.107.182',
    //         console_redis_password: '',
    //         redis_handle_pub: null,
    //         redis_handle_sub: null,
    //         redis_reday_pub: false,
    //         redis_reday_sub: false,
    //     }
    // ];
    let sql_select = "SELECT * FROM deploy_respool_area";
    uim.db_query(sql_select, function (err, results, fields) {
        if (err) {
            return console.log('查询可用区失败！');
        }
        // return;
        for (var tmp_i in results) {
            respool_area_list[results[tmp_i].respool_area_id] = {
                respool_id: results[tmp_i].respool_id,
                respool_area_id: results[tmp_i].respool_area_id,
                respool_area_name: results[tmp_i].respool_area_name,
                description: results[tmp_i].description,
                console_redis_port: results[tmp_i].console_redis_port,
                console_redis_host: results[tmp_i].console_redis_host,
                console_redis_password: results[tmp_i].console_redis_password,
                redis_handle_pub: null,
                redis_handle_sub: null,
                redis_reday_pub: false,
                redis_reday_sub: false,
                redis_retry_times: 0,
            }
            connect_respool_area_redis_pub(respool_area_list[results[tmp_i].respool_area_id]); // 连接控制台
        }
    });
}
var all_redis_state = function () {
    let pub_success_count = 0, sub_success_count = 0, total = 0;
    for (var tmp_i in respool_area_list) {
        total++;
        respool_area_list[tmp_i].redis_reday_pub && pub_success_count++;
        respool_area_list[tmp_i].redis_reday_sub && sub_success_count++;
    }
    console.log('共' + total + '个可用区，连接成功：pub ' + pub_success_count + ' / sub ' + sub_success_count + '个');
    if (total == pub_success_count && total == sub_success_count) {
        console.log('====================================所有可用区控制台就绪====================================')
    }
}
var connect_respool_area_redis_pub = function (obj_area) {
    obj_area.redis_handle_pub = redis.createClient(obj_area.console_redis_port, obj_area.console_redis_host, {
        auth_pass: obj_area.console_redis_password
    });
    obj_area.redis_handle_pub.on('ready', function (err) {
        if (err) {
            console.log(err);
            console.log('地区“' + obj_area.respool_area_name + '”--------连接控制台失败(pub)');
        } else {
            obj_area.redis_reday_pub = true;
            obj_area.redis_retry_times = 0;
            console.log('地区“' + obj_area.respool_area_name + '”已连接到控制台(pub)');
            connect_respool_area_redis_sub(obj_area);
        }
        all_redis_state();
    }).on('error', function (err) {
        obj_area.redis_reday_pub = false;
        obj_area.redis_retry_times++;
        console.log('地区“' + obj_area.respool_area_name + '”--------连接控制台失败(pub)-2');
        if (obj_area.redis_retry_times > ENV._REDIS_RETRY_COUNT_MAX) {
            console.log('redis重连达到次数限制 - 可用区：' + obj_area.respool_area_name)
            obj_area.redis_handle_pub.quit();
            obj_area.redis_handle_sub && obj_area.redis_handle_sub.quit();
            // console.log(obj_area);
        }
        all_redis_state();
        // console.log({
        //     msg: 'redis pub连接错误 - 可用区：' + obj_area.respool_area_name,
        //     err
        // })
    });
}

var connect_respool_area_redis_sub = function (obj_area) {
    if (obj_area.redis_handle_sub) {
        return; // 已经初始化
    }
    obj_area.redis_handle_sub = redis.createClient(obj_area.console_redis_port, obj_area.console_redis_host, {
        auth_pass: obj_area.console_redis_password
    });
    obj_area.redis_handle_sub.on('ready', function (err) {
        if (err) {
            console.log(err);
            console.log('地区“' + obj_area.respool_area_name + '”--------连接控制台失败(sub)');
        } else {
            obj_area.redis_reday_sub = true;
            obj_area.redis_retry_times = 0;
            console.log('地区“' + obj_area.respool_area_name + '”已连接到控制台(sub)');
        }
        all_redis_state();
    }).on('error', function (err) {
        obj_area.redis_reday_sub = false;
        obj_area.redis_retry_times++;
        console.log('地区“' + obj_area.respool_area_name + '”--------连接控制台失败(sub)-2');
        if (obj_area.redis_retry_times > ENV._REDIS_RETRY_COUNT_MAX) {
            console.log('redis重连达到次数限制 - 可用区：' + obj_area.respool_area_name)
            obj_area.redis_handle_pub.quit();
            obj_area.redis_handle_sub && obj_area.redis_handle_sub.quit();
            // console.log(obj_area);
        }
        all_redis_state();
        // console.log({
        //     msg: 'redis sub连接错误 - 可用区：' + obj_area.respool_area_name,
        //     err
        // })
    });
    obj_area.redis_handle_sub.subscribe('console'); // 订阅控制台消息
    obj_area.redis_handle_sub.on('subscribe', function (channel, count) {
        console.log(`got subscribe event: ${channel} and count is ${count}`);
    });
    obj_area.redis_handle_sub.on('connect', function () {
        //订阅客户端接收到消息
        obj_area.redis_handle_sub.on('message', function (channel, message) {
            var time = new Date().getTime();
            var response = `${time} received message from ${channel}:${message}`;
            console.log(response);
            console.log('收到控制台消息 - 可用区：' + obj_area.respool_area_name)
            switch (channel) {
                case 'console':
                    // emit_event(message, time);
                    console.log(message, time);
                // case 'debug':
                //     run_debug(message);
                default:
                    break;
            }
        });
    });

}
var redis = require('redis');
const { send } = require('process');
const { SSL_OP_SSLEAY_080_CLIENT_DH_BUG } = require('constants');


session_redis = redis.createClient(ENV.REDIS.PORT, ENV.REDIS.HOST, {
    auth_pass: ENV.REDIS.PASSWORD
});
session_redis.on('ready', function (err) {
    if (err) {
        console.log(err);
        console.log('连接redis（会话）失败');
    } else {
        console.log('连接redis（会话）成功');
    }
}).on('error', function () {
    console.log('连接redis会话服务器失败！')
});

session_list = {}; // 服务器本机会话（本系统只须运行一个后端服务器，因此可以保留一份在服务器本机）
// 只在程序启动和socket断开时更新会话过期时间
function set_session_expire(session_id) {
    if (ENV._SESSION_EXPIRE) {
        console.log('设置过期时间：', session_id, ENV._SESSION_EXPIRE);
        session_redis.expire(ENV.SESSION_PREFIX + session_id, ENV._SESSION_EXPIRE);
    }
}
function save_session(session_id, callback) {
    let session_json = JSON.stringify(session_list[session_id]);
    if (session_json.length > ENV.SESSION_SIZE_MAX) {
        load_session(session_id); // 重新载入会话数据
        return callback('会话信息超过大小限制！当前大小：' + session_json.length + '；限制大小：' + ENV.SESSION_SIZE_MAX);
    }
    session_redis.set(ENV.SESSION_PREFIX + session_id, session_json, function (err, result) {
        if (err) {
            callback('更新会话信息失败！');
        } else {
            callback();
        }
    });
}
function get_session(session_id, callback) {
    if (session_list[session_id]) {
        callback(session_list[session_id]);
    } else {
        load_session(session_id, callback); // 重新载入会话数据
    }
}
function create_session(session_id, client_id, callback) {
    // session = {
    //     session_id, client_id, session_data
    // }
    session_list[session_id] = {
        session_id,
        client_id,
        session_data: {}
    };
    save_session(session_id, callback);
}
function load_session(session_id, callback) {
    session_redis.get(ENV.SESSION_PREFIX + session_id, function (err, result) {
        if (result) {
            session_list[session_id] = JSON.parse(result);
            callback && callback(session_list[session_id]);
        } else {
            // 读取会话信息失败
            warning_log({
                time: '',
                category: 1,
                title: '读取会话信息失败',
                content: session_id
            });
            callback && callback(null);
        }
    });
}
function init_session_list() {
    session_redis.keys(ENV.SESSION_PREFIX + '*', function (err, results) {
        if (err) {
            warning_log({ time: '', category: 1, title: '获取历史会话信息出错', content: err });
        } else {
            for (var tmp_i in results) {
                session_redis.expire(results[tmp_i], ENV._SESSION_EXPIRE);
            }
            console.log('已将所有会话信息重新设置到期时间，会话信息数量：' + results.length);
        }
    });
}
function getClientIp(req) {
    return req.headers['x-forwarded-for'] ||
        req.connection.remoteAddress ||
        req.socket.remoteAddress ||
        req.connection.socket.remoteAddress;
};
var tmp_view = {}; // 存放临时视图（当客户端浏览器为IE等非现代浏览器时使用http转现）
// 设置临时视图
var set_tmp_view = function (page_id, html) {
    tmp_view[page_id] = html;
    setTimeout(function () {
        delete tmp_view[page_id];
    }, 5000);
}
// 获取临时视图
var get_tmp_view = function (page_id) {
    return tmp_view[page_id] || '<html><body><center><h1>视图已失效</h1><hr>uim tmp view.</center></body></html>';
}
var app = http.createServer(function (req, res) {
    // res.writeHead(200, {
    //     // 'Content-Type': 'application/json',
    //     'Access-Control-Allow-Origin': '*'
    // });
    //GET
    var obj = urlLib.parse(req.url, true);
    var url = obj.pathname;
    const GET = obj.query;

    //POST
    var str = '';
    var POST = '';
    req.on('data', function (data) {
        str += data;
    });
    req.on('end', function () {
        POST = qs.parse(str);
        console.log({ req_url: req.url, url, GET, POST, method: req.method });
        if (req.method == 'GET') {
            if (url == '/') {
                url = '/index.html';
            } else if (url == '/get-tmp-view') {
                res.writeHead(200, {
                    'Content-Type': 'text/html'
                });
                res.end(get_tmp_view(GET.page_id));
                return;
            }
            fs.readFile('./static' + url, function (err, data) {
                if (err) {
                    res.writeHead(404, {
                        'Content-Type': 'text/html'
                    });
                    res.end('<html><center><h1>404 file not found.</h1><hr>uim-console v1.0</center>');
                } else {
                    res.end(data);
                }
            });
        } else if (req.method == 'POST') {
            if (url == '/set-tmp-view') {
                var post_keys = Object.keys(POST);
                var tmp_keys = post_keys[0].split('\n')[0].trim();
                var html = POST[post_keys[0]].split(tmp_keys)[0].split(tmp_keys)[0].split('\n');
                html.shift(); html.shift();// html.shift();
                html = html.join('\n').trim();

                var page_id = new Date().getTime() + '-' + uim.md5(html);
                set_tmp_view(page_id, html);
                res.writeHead(200, {
                    'Content-Type': 'application/json',
                    'Access-Control-Allow-Origin': '*'
                });

                res.end(JSON.stringify({ page_id }));
            }
        } else {
            res.end('请求方法不支持：' + req.method);
        }
    });
}).listen(ENV.LISTEN_PORT);
var io = require('socket.io').listen(app);
var online_client_number = 0;
io.sockets.on('connection', function (socket) {
    online_client_number++;
    console.log(uim.dateTime() + ' - 客户端连接：' + socket.request.connection.remoteAddress +
        '。在线总人数：' + online_client_number + '。socket.id：' + socket.id);

    // 客户端发起初始校验请求
    socket.emit('init');

    // 校验
    socket.on('check', function (check_data, callback) {
        // check_data = {
        //     init_id: uim.init_id,
        //     deploy_app_id: uim.init_param.deploy_app_id,
        //     session_id: uim.session.id
        // }
        var check_result = {
            // init_id:'',
            // session_id:'',
            // account_id:'',
        };
        var app_id, client_id, session_id;
        // 校验应用编号
        var check_deploy_app_id = function () {
            // 开始校验应用编号
            var verify_deploy_app_id = uim.verifySafeString(check_data.deploy_app_id, uim.config.enum.DEPLOY_APP_ID);
            if (!verify_deploy_app_id) {
                callback('校验失败(deploy_app_id)');
            } else if (verify_deploy_app_id.id != ENV.APP_ID) {
                callback('应用编号不符！'); // 此处只校验一个应用，直接判断是否等于环境配置中的应用编号即可
            } else {
                app_id = verify_deploy_app_id.id;
                check_init_id();
            }
        }
        // 校验初始编号
        var check_init_id = function () {
            // 校验初始编号
            if (check_data.init_id) {
                var verify_init_id = uim.verifySafeString(check_data.init_id);
                if (!verify_init_id) {
                    callback('校验失败(init_id)');
                } else {
                    // 校验init_id通过，继续检查与数据库中的信息是否匹配
                    client_id = verify_init_id.id;
                    let sql_check_client_info = "SELECT * FROM request_client WHERE client_id = " + client_id + " LIMIT 1";
                    uim.db_query(sql_check_client_info, function (err, results, fields) {
                        if (err) {
                            return callback('数据库查询出错：' + err);
                        } else if (results[0].deploy_app_id != check_data.deploy_app_id) {
                            return callback('应用编号与客户端初始编号不符合！');
                        }
                        // 如果init_id与last_init_id不对应，则记录警告日志
                        if (results[0].last_init_id && results[0].last_init_id != check_data.init_id) {
                            warning_log({
                                time: '',
                                category: 1,
                                title: 'init_id与last_init_id不对应',
                                content: '可能是同时打开两个浏览器窗口导致'
                            });
                        }


                        // 写入初始日志
                        let sql_insert_client_init_log = "INSERT INTO request_client_init_log " +
                            "(init_id, client_id, client_ip, log_time, url, referrer, socket_id, app_id, headers)" +
                            "VALUES ('" + check_data.init_id + "', " +
                            client_id + ", '" + socket.request.connection.remoteAddress + "', '" +
                            uim.dateTime() + "', " + mysql.escape(check_data.url) + ", " +
                            mysql.escape(check_data.referrer) + ", '" + socket.id + "'," + app_id + "," +
                            mysql.escape(JSON.stringify(socket.handshake.headers)) + ")";

                        uim.db_query(sql_insert_client_init_log, function (err, results, fields) {
                            if (err) {
                                return callback('数据库查询出错：' + err);
                            }
                            socket.init_log_id = results.insertId;
                            // 使用原client_id生成新的init_id
                            check_result.init_id = uim.createSafeString({
                                int_unique: client_id,
                                int_tag: uim.config.enum.CLIENT_ID,
                            });

                            // 更新当前客户端的last_init_id
                            let sql_update_client_last_init_id = "UPDATE request_client SET last_init_id ='" + check_result.init_id +
                                "', last_check_time ='" + uim.dateTime() + "' WHERE client_id = " + client_id + " LIMIT 1";
                            uim.db_query(sql_update_client_last_init_id,
                                function (err, results, fields) {
                                    if (err) {
                                        return callback('数据库查询出错：' + err);
                                    }
                                    check_session_id();
                                }
                            );
                        });
                    });
                }
            } else {
                if (ENV._REJECT_NEW_CLIENT) {
                    callback('服务器已禁止新的客户端连接');
                } else {
                    // 允许新客户端连接，则创建新client_id

                    let sql_insert_new_client = "INSERT INTO request_client (deploy_app_id, create_time) VALUES ( '" +
                        check_data.deploy_app_id + "', '" + uim.dateTime() + "')";

                    uim.db_query(sql_insert_new_client, function (err, results, fields) {
                        if (err) {
                            return callback('数据库查询出错：' + err);
                        }
                        // 根据新创建的client_id返回init_id
                        client_id = results.insertId;
                        check_result.init_id = uim.createSafeString({
                            int_unique: client_id,
                            int_tag: uim.config.enum.CLIENT_ID,
                        });
                        check_session_id();
                    });
                }
            }
        }
        // 校验会话编号
        var check_session_id = function () {
            // 校验初始编号
            if (check_data.session_id) {
                var verify_session_id = uim.verifySafeString(check_data.session_id, uim.config.enum.SESSION_ID);
                if (!verify_session_id) {
                    callback('校验失败(session_id)');
                } else {
                    // // 查询当前会话
                    get_session(verify_session_id.id, function (session) {
                        if (!session) {
                            // 如果会话编号已经过期，重新执行本函数，并走到创建session_id逻辑中
                            check_data.session_id = '';
                            return check_session_id();
                        }
                        // if (session.app_id != app_id) {
                        //     return callback('应用编号与会话编号不符合！');
                        // }
                        if (session.client_id != client_id) {
                            return callback('客户端编号与会话编号不符合！');
                        }
                        // 如果会话中有登录账户信息，则返回给前端
                        if (session.session_data.account_id) {
                            check_result.account_id = uim.createSafeString({
                                int_unique: session.session_data.account_id,
                                int_tag: uim.config.enum.ACCOUNT_ID,
                            });
                        }
                        socket.session_id = session_id = verify_session_id.id;
                        // 使用原(int)session_id生成新的session_id安全字串
                        check_result.session_id = uim.createSafeString({
                            int_unique: session_id,
                            int_tag: uim.config.enum.SESSION_ID,
                        });

                        // todo 是否写日志？
                        callback(0, check_result);

                    });
                }
            } else {
                if (ENV._REJECT_NEW_SESSION) {
                    callback('服务器已禁止新的会话');
                } else {
                    // 允许新会话
                    let now_time = uim.dateTime();
                    let sql_insert_new_session = "INSERT INTO request_session (app_id, create_time, create_ip, client_id) VALUES ( '" +
                        app_id + "', '" + now_time + "', '" + socket.request.connection.remoteAddress + "'," + client_id + ")";

                    uim.db_query(sql_insert_new_session, function (err, results, fields) {
                        if (err) {
                            return callback('数据库查询出错：' + err);
                        }
                        socket.session_id = session_id = results.insertId;
                        create_session(session_id, client_id, function (err) {
                            if (err) {
                                return callback('创建会话信息出错：' + err);
                            }
                            check_result.session_id = uim.createSafeString({
                                int_unique: session_id,
                                int_tag: uim.config.enum.SESSION_ID,
                            });
                            callback(0, check_result);

                        });
                    });
                }
            }
        }
        // 开始校验
        check_deploy_app_id();
    });
    // 接口
    socket.on('api', function (req, callback) {
        if (!socket.session_id) {
            return callback({
                code: 1,
                data: null,
                text: '未进行会话校验，禁止调用接口！'
            });
        }
        get_session(socket.session_id, function (session) {
            if (!session) {
                // 会话不存在
                return callback({
                    code: 1,
                    data: null,
                    text: '内部异常[会话不存在]'
                });
            }
            run_api(req, session, function (data) {
                callback(data);
            });
        });
    });

    // 调试
    socket.on('debug', function (debug_code) {
        console.log('debug: ' + debug_code);
        //此调试方法只在调试模式下使用
        if (ENV._DEBUG_MODE) eval(debug_code);
    });

    socket.on('disconnect', function (data) {
        online_client_number--;
        let now_time = uim.dateTime();
        console.log(now_time + ' - 客户端断开：' + socket.request.connection.remoteAddress +
            '。在线总人数：' + online_client_number + '。socket.id：' + socket.id);
        if (socket.init_log_id) {
            let sql_update_client_init_log = "UPDATE request_client_init_log SET leave_time='" + now_time +
                "' WHERE log_id = " + socket.init_log_id + " LIMIT 1";
            uim.db_query(sql_update_client_init_log, function (err, results, fields) {
                err && console.log('更新离线时间失败');
            });
        }
        if (socket.session_id) {
            // 单个客户端断开时，为其会话设置过期时间
            // session_list[socket.session_id].update_time = now_time;
            set_session_expire(socket.session_id);
            delete session_list[socket.session_id]; // 删除会话
            // let sql_update_session = "UPDATE request_session SET update_time='" + now_time +
            //     "' WHERE session_id = " + socket.session_id + " LIMIT 1";
            // uim.db_query(sql_update_session, function (err, results, fields) {
            //     err && console.log('更新会话时间失败');
            // });
        }
    });
});

uim.apis = {};
var list_folder_file = function (path, callback) {
    fs.stat(path, function (err, stats) {
        //如果是目录的话，遍历目录下的文件信息
        if (stats.isDirectory()) {
            fs.readdir(path, function (err, file) {
                file.forEach((e) => {
                    list_folder_file(path + '/' + e, callback)
                });
            })
        } else {
            callback(path);
        }
    });
}

// 载入接口函数
// uim.apis = {};
list_folder_file(ENV.APP_PATH + 'api', function (path) {
    var api_code = path.substr(ENV.APP_PATH.length).split('.')[0].split('/');
    api_code.shift();
    api_code = api_code.join('.');
    uim.apis[api_code] = require('./' + path)[api_code];

    // console.log('接口初始成功', api_code + ' from ' + path);
    // console.log('----------------------------------------------');
    // console.log(Object.keys(uim.apis));
});

// 载入公共函数
uim.commons = {};
list_folder_file(ENV.APP_PATH + 'common', function (path) {
    var common_code = path.substr(ENV.APP_PATH.length).split('.')[0].split('/');
    common_code.shift();
    common_code = common_code.join('.');
    uim.commons[common_code] = require('./' + path)[common_code];

    // console.log('公共函数初始成功', common_code + ' from ' + path);
    // console.log('----------------------------------------------');
    // console.log(Object.keys(uim.commons));

});

// 载入业务配置
uim.params = {};
list_folder_file(ENV.APP_PATH + 'param', function (path) {
    var param_code = path.substr(ENV.APP_PATH.length).split('.')[0].split('/');
    param_code.shift();
    param_code = param_code.join('.');
    uim.params[param_code] = require('./' + path)[param_code];

    console.log('业务参数初始成功', param_code + ' from ' + path);
    console.log('----------------------------------------------');
    // console.log(Object.keys(uim.params));

});

// 载入业务枚举
uim.enums = {};
list_folder_file(ENV.APP_PATH + 'enum', function (path) {
    var enum_code = path.substr(ENV.APP_PATH.length).split('.')[0].split('/');
    enum_code.shift();
    enum_code = enum_code.join('.');
    uim.enums[enum_code] = require('./' + path)[enum_code];

    console.log('枚举对象初始成功', enum_code + ' from ' + path);
    console.log('----------------------------------------------');
    // console.log(Object.keys(uim.enums));

});

var run_api_working_count = 0;
var run_api = function (req, session, callback) {
    if (run_api_working_count > ENV._API_WORKING_MAX) {
        callback({
            code: 1,
            data: '触发限流',
            text: '服务器繁忙'
        })
    }
    var api_code = req.code.split('/');
    if (!api_code[1]) {
        api_code[1] = '1.0';
    }
    console.log({ req })
    var obj_class = uim.apis[api_code[0]];
    console.log({ obj_class })
    if (!obj_class || !obj_class[api_code[1]]) {
        return callback({
            code: 1,
            data: '调用接口失败',
            text: '接口不存在'
        })
    }
    run_api_working_count++;
    var api_run_complete = false; // 接口是否执行完毕，用于判断是否超时
    var json_session_data_old = JSON.stringify(session.session_data);
    setTimeout(function () {
        if (api_run_complete) return;
        api_run_complete = true;
        run_api_working_count--;
        let json_session_data_new = JSON.stringify(session.session_data);
        // 如果session发生了变化，则等更新了session再返回接口
        if (json_session_data_old != json_session_data_new) {
            save_session(session.session_id, function (err) {
                err && warning_log({
                    time: '',
                    category: 1,
                    title: '会话信息持久化失败',
                    content: ''
                });
                callback({
                    code: 1,
                    data: null,
                    text: '接口执行超时'
                });
            });
        } else {
            callback({
                code: 1,
                data: null,
                text: '接口执行超时'
            });
        }
    }, ENV._API_TIMEOUT);
    try {
        // 直接将session的引用传入接口
        obj_class[api_code[1]](req.data, session.session_data, function (code, data, text) {
            if (api_run_complete) return;
            api_run_complete = true;
            run_api_working_count--;
            let json_session_data_new = JSON.stringify(session.session_data);
            // 如果session发生了变化，则等更新了session再返回接口
            if (json_session_data_old != json_session_data_new) {
                save_session(session.session_id, function (err) {
                    err && warning_log({
                        time: '',
                        category: 1,
                        title: '会话信息持久化失败',
                        content: ''
                    });
                    callback({
                        code,
                        data,
                        text,
                    });
                });
            } else {
                callback({
                    code,
                    data,
                    text,
                });
            }
        });
    } catch (e) {
        if (api_run_complete) return;
        api_run_complete = true;
        run_api_working_count--;
        console.log(e);
        let json_session_data_new = JSON.stringify(session.session_data);
        // 如果session发生了变化，则等更新了session再返回接口
        if (json_session_data_old != json_session_data_new) {
            save_session(session.session_id, function (err) {
                err && warning_log({
                    time: '',
                    category: 1,
                    title: '会话信息持久化失败',
                    content: ''
                });
                callback({
                    code: 1,
                    data: e,
                    text: '接口执行出错',
                });
            });
        } else {
            callback({
                code: 1,
                data: e,
                text: '接口执行出错',
            });
        }
    }
}
var warning_log = function (obj_warn) {
    console.log('----------------------------------------------');
    console.log('发出警告：')
    obj_warn.time = obj_warn.time || uim.dateTime();
    console.log(obj_warn)
}
console.log('uim console is running: ' + uim.dateTime());
console.log('----------------------------------------------');
init_respool_area_list();
init_session_list();